#include <gtest/gtest.h>

#include <condition_variable>
#include <mutex>
#include <thread>

using namespace std::chrono_literals;

// 演示 std::condition_variable 搭配 std::unique_lock 的典型用法。
// 一个线程等待条件满足，另一个线程设置标志并通知。
TEST(ConditionVariableTest, NotifiesWaitingThread) {
    std::mutex m;
    std::condition_variable cv;
    bool ready = false;

    // 生产者线程：稍作等待后设置 ready = true 并通知等待者。
    std::thread worker([&] {
        std::this_thread::sleep_for(5ms);
        {
            std::lock_guard<std::mutex> lock(m);
            ready = true;
        }
        cv.notify_one();
    });

    // 消费者线程：等待条件变量直到 ready 为 true。
    std::unique_lock<std::mutex> lock(m);
    cv.wait(lock, [&] { return ready; });
    lock.unlock();

    worker.join();
    EXPECT_TRUE(ready);
}

// 场景 1：生产者在 5ms 后设置 ready 并通知等待者。
// 消费者使用 wait_for，每次等待 2ms，若超时则记录超时次数并继续检查。
// 最终在多次超时后仍能得到 ready == true。
TEST(ConditionVariableTest, WaitForRetriesUntilReady) {
    std::mutex m;
    std::condition_variable cv;
    bool ready = false;
    int timeoutCount = 0;

    std::thread producer([&] {
        std::this_thread::sleep_for(5ms);
        {
            std::lock_guard<std::mutex> lock(m);
            ready = true;
        }
        cv.notify_one();
    });

    std::unique_lock<std::mutex> lock(m);
    while (!ready) {
        // wait_for 返回 false 表示超时，true 表示谓词已满足
        if (!cv.wait_for(lock, 2ms, [&] { return ready; })) {
            ++timeoutCount; // 超时后可执行重试、日志、降级等逻辑
        }
    }
    lock.unlock();

    producer.join();
    EXPECT_TRUE(ready);
    EXPECT_GE(timeoutCount, 1); // 至少发生一次超时（具体次数取决于调度）
}

// 场景 2：尝试在截止时间前等候配置加载完成。
// 若超时（ready 未在截止时间前变为 true），触发降级路径。
TEST(ConditionVariableTest, WaitUntilTimesOutWhenDeadlineReached) {
    std::mutex m;
    std::condition_variable cv;
    bool ready = false;

    // 本例故意不启动任何生产者线程，模拟迟迟未完成的任务。

    std::unique_lock<std::mutex> lock(m);
    const auto deadline = std::chrono::steady_clock::now() + 3ms;

    bool completed = cv.wait_until(lock, deadline, [&] { return ready; });
    lock.unlock();

    EXPECT_FALSE(completed);  // 超时返回 false，表示条件未满足
    EXPECT_FALSE(ready);      // ready 仍为 false
}